package org.lab.tracecash.io;

import static org.lab.tracecash.model.RuleEvaluationSource.LongDesc;
import static org.lab.tracecash.model.RuleEvaluationSource.ShortDesc;
import static org.lab.tracecash.model.RuleEvaluationType.Contains;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import org.apache.commons.lang.Validate;
import org.lab.tracecash.Constants;
import org.lab.tracecash.bootstrap.TracecashBootstrap;
import org.lab.tracecash.guice.TracecashCoreModule;
import org.lab.tracecash.io.bankia.BankiaCsvImporter;
import org.lab.tracecash.model.Account;
import org.lab.tracecash.model.Transaction;
import org.lab.tracecash.model.TransactionResolverRule;
import org.lab.tracecash.model.User;
import org.lab.tracecash.model.UserPreferences;
import org.lab.tracecash.services.AccountService;
import org.lab.tracecash.services.CommonAccountGenerator;
import org.lab.tracecash.services.TransactionRuleExecutor;
import org.lab.tracecash.services.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.persist.PersistService;

/**
 * This class creates a dummy user and loads some transactions from a CSV file
 */
public class DemoUserCreator implements Runnable {

	private static final Logger LOG = LoggerFactory.getLogger(DemoUserCreator.class);
	private static final String DEMO_USER_NAME = "demo";
	private static final String DEMO_USER_MAIL = "demo@tracecash.com";
	private static final String DEMO_TRANSACTION_FILE = "demo/transactions.csv";

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new TracecashCoreModule());
		injector.getInstance(PersistService.class).start();
		injector.getInstance(DemoUserCreator.class).run();
	}

	@Inject
	private Provider<EntityManager> entityManagerProvider;
	@Inject
	private AccountService accountService;
	@Inject
	private CommonAccountGenerator commonAccountGenerator;
	@Inject
	private BankiaCsvImporter csvImporter;
	@Inject
	private TransactionRuleExecutor ruleExecutor;
	@Inject
	private UserService userService;
	@Inject
	private TracecashBootstrap bootstrap;

	@Override
	public void run() {
		if (!bootstrap.isDatabaseInitialized()) {
			bootstrap.run();
		}
		User dummyUser = userService.findByEmail(DEMO_USER_MAIL);
		if (dummyUser != null) {
			LOG.info("Dummy user already exists");
		} else {
			EntityManager entityManager = entityManagerProvider.get();
			if (!entityManager.getTransaction().isActive()) {
				entityManager.getTransaction().begin();
			}
			createDummyUser();
			loadDummyOperations();
			createDummyRules();
			ruleExecutor.execute(userService.findByEmail(DEMO_USER_MAIL));
			if (entityManager.getTransaction().isActive()) {
				entityManager.getTransaction().commit();
			}
			printUnclassifiedOperations();
		}
	}

	private void createDummyUser() {
		EntityManager entityManager = entityManagerProvider.get();
		LOG.info("Creando usuario dummy");
		User user = new User(DEMO_USER_NAME, DEMO_USER_MAIL, null, Calendar.getInstance().getTime());
		user.setPreferences(new UserPreferences());
		user.getPreferences().setLanguage("es_ES");
		user.setPasswordDigest("dummy");
		commonAccountGenerator.generateCommonsAccounts(user);
		entityManager.persist(user);
		entityManager.flush();
	}

	private void loadDummyOperations() {
		EntityManager entityManager = entityManagerProvider.get();
		InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(DEMO_TRANSACTION_FILE);
		Validate.notNull(in, "Missing resource " + DEMO_TRANSACTION_FILE);
		User user = userService.findByEmail(DEMO_USER_MAIL);
		Account source = accountService.getByName(Constants.ACC_VOID, user.getId());
		Account target = accountService.getByName(Constants.ACC_UNCLASSIFIED, user.getId());
		List<Transaction> list = csvImporter.parse(source, target, in);
		for (Transaction i : list) {
			i.setAmount(i.getAmount().abs());
			entityManager.persist(i);
		}
		entityManager.flush();
	}

	private void createDummyRules() {
		EntityManager entityManager = entityManagerProvider.get();
		List<TransactionResolverRule> list = new ArrayList<TransactionResolverRule>();
		User user = userService.findByEmail(DEMO_USER_MAIL);

		Account income = accountService.getByName(Constants.ACC_INCOME, user.getId());
		Account salary = accountService.getByName(Constants.ACC_SALARY, user.getId());
		Account cashInWallet = accountService.getByName(Constants.ACC_CASH_IN_WALLET, user.getId());
		Account rent = accountService.getByName(Constants.ACC_RENT, user.getId());
		Account home = accountService.getByName(Constants.ACC_HOME, user.getId());
		Account food = accountService.getByName(Constants.ACC_FOOD, user.getId());
		Account foodHome = accountService.getByName(Constants.ACC_FOOD_HOME, user.getId());
		Account publicTransportation = accountService.getByName(Constants.ACC_PUBLIC_TRANSPORTATION, user.getId());
		Account taxes = accountService.getByName(Constants.ACC_TAXES, user.getId());
		Account phone = accountService.getByName(Constants.ACC_PHONE, user.getId());
		Account bankFees = accountService.getByName(Constants.ACC_BANK_FEES, user.getId());
		Account pets = accountService.getByName(Constants.ACC_PETS, user.getId());
		Account education = accountService.getByName(Constants.ACC_EDUCATION, user.getId());
		Account games = accountService.getByName(Constants.ACC_GAMES, user.getId());
		Account leisures = accountService.getByName(Constants.ACC_LEISURES, user.getId());
		Account health = accountService.getByName(Constants.ACC_HEALTH, user.getId());
		Account computer = accountService.getByName(Constants.ACC_COMPUTER, user.getId());
		Account entertainment = accountService.getByName(Constants.ACC_ENTERTAINMENT, user.getId());
		Account subscriptions = accountService.getByName(Constants.ACC_SUBSCRIPTIONS, user.getId());

		list.add(new TransactionResolverRule(LongDesc, Contains, "WILDBUNCH", null, salary));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "reintegro cajero automatico", income, cashInWallet));
		list.add(new TransactionResolverRule(LongDesc, Contains, "reintegro cajero automatico", income, cashInWallet));

		list.add(new TransactionResolverRule(LongDesc, Contains, "yoigo", income, phone));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "recibo de telefono", income, phone));
		list.add(new TransactionResolverRule(LongDesc, Contains, "recibo de telefono", income, phone));

		list.add(new TransactionResolverRule(LongDesc, Contains, "ELENA VERGAR CASTELL", income, rent));

		list.add(new TransactionResolverRule(LongDesc, Contains, "iberdrola", income, home));
		list.add(new TransactionResolverRule(LongDesc, Contains, "recibo de luz", income, home));

		list.add(new TransactionResolverRule(LongDesc, Contains, "riotgames", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "RIOTGAM", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "blizzard", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "diablo iii", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "diabloiii", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "diabloiii", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "diablo lll", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "metropolis", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "game preciados", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "world of warcraft", income, games));
		list.add(new TransactionResolverRule(LongDesc, Contains, "paypal", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "fnac", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "GAMES WORKSHOP", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "STEAMGAMES.COM", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "HEART OF THE SWARM", income, games));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "magic online", income, games));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "bar santos", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "alcala unodoscinco", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "alcala 125", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "the cavern", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "balua", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "el patin de oro", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "MALLORCA COMANDANT", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "taberna aranzazu", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "oharas", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "mi taska", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "la americana", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "bar el buho", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "BAR EL PUNTO DE EN", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "soul station", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "el narizotas", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "ribs", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "BAHIANA CLUB", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "AMARILLO DE NAPOLE", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "EL FOGON DE BACO", income, leisures));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "EL VAGON DE LA CER", income, leisures));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "TICK TACK TICKET", income, entertainment));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "tengo entradas.com", income, entertainment));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "vacaciones edreams", income, entertainment));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "MEL3 MUSIC SL", income, entertainment));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "razer", income, computer));

		list.add(new TransactionResolverRule(LongDesc, Contains, "just-eat", income, foodHome));
		list.add(new TransactionResolverRule(LongDesc, Contains, "sindelantal", income, foodHome));
		list.add(new TransactionResolverRule(LongDesc, Contains, "telepizza", income, foodHome));

		list.add(new TransactionResolverRule(LongDesc, Contains, "trabajo social y s", income, taxes));
		list.add(new TransactionResolverRule(LongDesc, Contains, "seguros sociales", income, taxes));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "seguros sociales", income, taxes));
		list.add(new TransactionResolverRule(LongDesc, Contains, "RECIBO IMPUESTOS O CONTRIBUCION", income, taxes));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "RECIBO IMPUESTOS O", income, taxes));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "cargo por cobro de servicios", income, bankFees));
		list.add(new TransactionResolverRule(LongDesc, Contains, "cargo por cobro de servicios", income, bankFees));
		list.add(new TransactionResolverRule(LongDesc, Contains, "cargo cuota anual tarjeta", income, bankFees));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "metro de madrid", income, publicTransportation));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "metro ligero", income, publicTransportation));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "licencia ", income, publicTransportation));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "METRO DE MADR", income, publicTransportation));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "renfe", income, publicTransportation));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "ryanair", income, publicTransportation));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "taxi", income, publicTransportation));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "supersol", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "estay pinchos", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "coviran", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "caprabo", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "algodor", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "mi cota", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "restaurante mico", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "RESTARAURANTE MICO", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "restaurante la ley", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "jabora restauracio", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "restaurante miroma", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "CAFETERIA VIPS GOY", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "entrepanes", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "tudespensa.com", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "CARREFOUR MARKET", income, food));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "BARRESTAURANTE OJO", income, food));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "zooplus", income, pets));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "TORVAL", income, education));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "AUSTRIAS CENTER", income, health));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "clinica dental", income, health));
		list.add(new TransactionResolverRule(ShortDesc, Contains, "blanes opticos", income, health));

		list.add(new TransactionResolverRule(ShortDesc, Contains, "adena", income, subscriptions));

		user.setRules(list);
		entityManager.merge(user);
	}

	private void printUnclassifiedOperations() {
		User user = userService.findByEmail(DEMO_USER_MAIL);
		Account account = accountService.getByName(Constants.ACC_UNCLASSIFIED, user.getId());
		EntityManager entityManager = entityManagerProvider.get();
		TypedQuery<Transaction> query = entityManager.createQuery("select a from Transaction a where a.to.id = :account", Transaction.class);
		List<Transaction> list = query.setParameter("account", account.getId()).getResultList();
		System.out.println("Conceptos no clasificados");
		for (Transaction i : list) {
			System.out.println("  " + i.getDesc() + " (" + i.getLongDesc() + "): " + i.getAmount());
		}
		System.out.println("Total: " + list.size());
	}
}
